#include <windows.h>
#include "../base/basic_types.h"
#include "simulator.h"

Simulator::Simulator()
: pCallBack(NULL)
, m_pCaseList(NULL)
, m_nInterval(TAC_ITV)
, m_nLoop(10000)
, m_nStatus(TAC_STATUS_OFFLINE)
, m_bSend(false)
, m_bStart(false)
, pCallSend(NULL)
{
	m_pCaseList = new CaseList;
}

Simulator::~Simulator()
{
	DB::Close();

	if(m_pCaseList)
	{
		delete m_pCaseList;
		m_pCaseList = NULL;
	}

	if(pCallBack)
	{
		delete pCallBack;
		pCallBack = NULL;
	}

	delete pCallSend;
}

int32 Simulator::Init()
{
	int32 nRt = 0;

	if((TAC::Init() == 0) && (DB::Init() == 0))		//init succeed
	{

	}
	else
	{
		nRt = -1;
	}

	return nRt;
}

int32 Simulator::Start()
{
	if(m_bStart == true)
		return -1;

	m_bStart = true;
	pthread_t tid;
	return pthread_create(&tid, NULL, thStart, this);
}

int32 Simulator::Stop()
{
	m_bStart = false;
	TAC::TAClose();
	return 0;
}

int32 Simulator::StartSend()
{
	if(m_bSend == true)
		return -1;

	m_bSend = true;
	return 0;
}

int32 Simulator::StopSend()
{
	if(m_bSend == false)
		return -1;

	m_bSend = false;
	return 0;
}

void Simulator::ClearCase()
{
	for(CaseList::iterator it = m_pCaseList->begin(); it != m_pCaseList->end();)
	{
		delete *it;
		it = m_pCaseList->erase(it);
	}
}

int32 Simulator::GetCase(int nDow, CaseList *pList)
{
	assert(pList);

	int nRt = 0;
	sqlite3_stmt *pStmt = NULL;

	char8 sql[256];
	sprintf(sql, "select case_id, case_dow, case_time, case_data, case_comment from test_case where case_dow = %d",
			nDow);

	nRt = DB::Query(sql, &pStmt);

	if(nRt == 0)
	{
		CASE *pCase = NULL;
		while(sqlite3_step(pStmt) == SQLITE_ROW)
		{
			pCase = new CASE;
			pCase->nID = sqlite3_column_int(pStmt, 0);
			pCase->nDow = sqlite3_column_int(pStmt, 1);
			memcpy(pCase->Time, (char8 *)sqlite3_column_blob(pStmt, 2), strlen((char8 *)sqlite3_column_blob(pStmt, 2)));
			memcpy(pCase->Data, (char8 *)sqlite3_column_blob(pStmt, 3), strlen((char8 *)sqlite3_column_blob(pStmt, 3)));
			memcpy(pCase->Comment, (char8 *)sqlite3_column_blob(pStmt, 4), strlen((char8 *)sqlite3_column_blob(pStmt, 4)));

			pList->push_back(pCase);
		}

		sqlite3_finalize(pStmt);
	}

#ifdef DEBUG
	printf("templist size:%d\n", pList->size());
#endif

	return nRt;
}

int32 Simulator::LoadCase(int nDow)
{
	if(nDow == -1)
		nDow = GetDayofWeek();

	CaseList list;
	GetCase(nDow, &list);

	ClearCase();

	m_pCaseList->assign(list.begin(), list.end());

#ifdef DEBUG
	printf("caselist size:%d\n", m_pCaseList->size());
#endif

	return 0;
}

int32 Simulator::AddCase(const CASE *pCase)
{
	assert(pCase);

	char8 sql[256];
	sprintf(sql, "insert into test_case(case_dow, case_time, case_data, case_comment) values(%d, '%s', '%s', '%s')",
			pCase->nDow, pCase->Time, pCase->Data, pCase->Comment);

	DB::Update(sql);

	return 0;
}

int32 Simulator::DeleteCase(uint32 nID)
{
	char8 sql[256];
	sprintf(sql, "delete from test_case where case_id = %d",
			nID);

	DB::Update(sql);

	return 0;
}

int32 Simulator::EditCase(const CASE *pCase)
{

	assert(pCase);

	char8 sql[256];
	sprintf(sql, "update test_case set case_dow = %d, case_time = %s, case_data = %s, case_comment = %s where case_id = %d",
			pCase->nDow, pCase->Time, pCase->Data, pCase->Comment, pCase->nID);

	DB::Update(sql);

	return 0;
}

void Simulator::SetStatus(int32 nStatus)
{

	if(m_nStatus != nStatus)
	{
		m_nStatus = nStatus;
		invoke(&m_nStatus);
	}
}

void *Simulator::thStart(void *pData)
{
	assert(pData);

	int nRt = 0;
	pthread_t tid;
	pthread_t tidsend;

	Simulator *pSim = (Simulator *)pData;
	pSim->SetStatus(TAC_STATUS_CONNECTING);

	while(pSim->IsStart())
	{
		nRt = pSim->TAStart();
		if(nRt == TA_SUCCESS)
		{
			//start check status
			pthread_create(&tid, NULL, Simulator::thCheckStatus, pData);
			pthread_create(&tidsend, NULL, Simulator::thSend, pData);
			break;
		}

		::Sleep(TAC_ITV);
	}

	return (void *)nRt;
}

void *Simulator::thSend(void *pData)
{
	assert(pData);
	Simulator *pSim = (Simulator *)pData;
	CASE *pCase = NULL;
	char buf[512];

	while(pSim->IsStart())
	{
		/* if((pSim->GetStatus() == TAC_STATUS_ONLINE) && (pSim->IsSend()))	//send
		{
			pCase = pSim->EnumCase();
			if(pCase)
			{
				pSim->TAPutMsgExt((char *)pCase->Data);
				pSim->invokeSend((char *)pCase->Data);
				//invode send
			}
		} */
		
		for(CaseList::iterator it = pSim->m_pCaseList->begin(); it != pSim->m_pCaseList->end(); ++it)
		{
			pCase = *it;
			if(pCase)
			{
				memset(buf, 0x0, sizeof(buf));
				memcpy(buf, (char *)pCase->Data, sizeof(pCase->Data));
				pSim->TAPutMsgExt(buf);
				pSim->invokeSend(buf);
				//invode send
			}
			
			::Sleep(180000);
		}

		
	}
}

void *Simulator::thCheckStatus(void *pData)
{
	assert(pData);
	Simulator *pSim = (Simulator *)pData;

	while(pSim->IsStart())
	{
		for(int i = 0; i < TAC_CHECKTIMES; ++i)
		{
			if(!pSim->IsStart())
				return 0;

			if(pSim->TAGetLinkStatus() == TA_LINKOK)
			{
				pSim->SetStatus(TAC_STATUS_ONLINE);
				break;
			}
			else
			{
				if(i == (TAC_CHECKTIMES - 1))
				{
					pSim->SetStatus(TAC_STATUS_OFFLINE);
				}
			}

			::Sleep(TAC_ITV);
		}
	}

}

CASE *Simulator::EnumCase()
{
	char time[8];
	GetShortTimeStr(time);

#ifdef DEBUG
	//printf("time: %s\n", time);
#endif

	return FindCaseByTime(time);
}

CASE *Simulator::FindCaseByTime(const char *pTime)
{
	assert(pTime);

	CASE *pCase = NULL;
	for(CaseList::iterator it = m_pCaseList->begin(); it != m_pCaseList->end(); ++it)
	{
		pCase = *it;

#ifdef DEBUG
	printf("pTime: %s   pCase->Time: %s\n", pTime, pCase->Time);
	for(int i = 0; i <7; ++i)
	{
		//if(pTime[i] == pCase->Time[i])
			printf("%c:%c\n", pTime[i], pCase->Time[i]);
	}
#endif
		if(strcmp(pTime, pCase->Time) == 0)
		{
			return pCase;
		}
	}

	return NULL;
}
